/* 
* Authors: Stefan Bojarovski <bojarovski@gmail.com>
*		   Dmitry Lebedev <leeevd@gmail.com>
* June,	2011
*/

#include "max_clique.h"
#include "simple_bt.h"
#include "bron_kerbosch.h"

using namespace boost;

// Reads a graph from a .dot file
bool graph_read(Graph& g, std::string input) 
{
	dynamic_properties dp;
	std::ifstream ifile(input.c_str());

	if(!ifile)
	{
		std::cerr << "Error: cannot open the file. \n";
		ifile.close();
		return false;
	}

	property_map<Graph, boost::vertex_name_t>::type name =
		get(vertex_name, g);
	dp.property("node_id",name);

	try
	{
		read_graphviz(ifile, g, dp, "node_id");
	}
	catch(bad_parallel_edge)
	{ 
		std::cout<<"Please, remove parallel edges\n";
		return false;
	}
	catch(undirected_graph_error)
	{ 
		std::cout<<"Tried to read an undirected graph into a directed graph.";
		return false;
	}
	catch(directed_graph_error)
	{ 
		std::cout<<"Tried to read a directed graph into an undirected graph.\n";
		return false;
	}
	ifile.close();
	return true;
}
// Labels a vertex that belongs to a maximal clique
void mark_vertex(Vertex v, Graph &g) 
{
	put(vertex_name, g, v, "max_clique");
}
// Writes a graph in a .dot file
void graph_write(Graph& g, VertexSet& maxClique, const char* file_name)
{
	std::ofstream file(file_name);             
	property_map<Graph, vertex_name_t>::type name = get(vertex_name, g);

	for(unsigned i = 0; i < maxClique.size(); i++)
	{
		mark_vertex(maxClique.at(i), g);
	}

	write_graphviz(file, g, make_label_writer(name));
	file.close();
}

int main() 
{
	clock_t start, end;
	std::string input;
	char option;
	char alg;
	char file_name[MAX_FILENAME_LENGTH];
	char* directory = "tests/";
	Graph inGraph;

	std::cout << "Please choose an option:" << std::endl;
	std::cout << "1. To test performance type 't'." << std::endl;
	std::cout << "2. To run an algotrithm type 'a'." << std::endl;
	std::cin >> option;

	switch(option)
	{
	case 't':
		{
			std::cout << "Performance testing from folder 'tests' : " << std::endl;
			performance_test();
			std::cout << "complete." << std::endl;
			std::cout << "Successfully written output to 'test_log.txt'." << std::endl;
			break;
		}
	case 'a':
		{
			std::cout << "Input files should be in the '/tests' folder:" << std::endl;
			std::cout << "Enter dot file name with graph:" << std::endl;
			std::cin >> input;
			sprintf_s(file_name, MAX_FILENAME_LENGTH, "%s%s", directory, input.c_str());

			if(!graph_read(inGraph, file_name))
			{
				system("pause>nul");
				return 0;
			}
			else
			{
				std::cout << "Please choose an algorithm:" << std::endl;
				std::cout << "1. For a simple backtracking algorithm type 's'." << std::endl;
				std::cout << "2. For the Bron-Kerbosch algorithm type 'b'." << std::endl;
				std::cin >> alg;

				switch(alg)
				{
				case 's':
					{
						std::cout << "Simple backtracking algorithm." << std::endl;
						simple_bt simple_solver(&inGraph);
						start = clock();
						simple_solver.do_simple_BT();
						end = clock();
						std::cout<< "Number of nodes: " << simple_solver.get_num_of_nodes() << std::endl;
						std::cout<< "Nodes in clique: " << simple_solver.get_maxClique().size() << std::endl;
						std::cout<< "Time: " << (double)(end - start) / CLOCKS_PER_SEC << std::endl;
						graph_write(inGraph, simple_solver.get_maxClique(), OUTPUT_FILE.c_str());
						break;
					}
				case 'b':
					{
						std::cout << "Bron-Kerbosch algorithm." << std::endl;
						bron_kerbosch bron_kerbosch_solver(&inGraph);
						start = clock();
						bron_kerbosch_solver.do_bron_kerbosch_BT();
						end = clock();
						std::cout<< "Number of nodes: " << bron_kerbosch_solver.get_num_of_nodes() << std::endl;
						std::cout<< "Nodes in clique: " << bron_kerbosch_solver.get_maxClique().size() << std::endl;
						std::cout<< "Time: " << (double)(end - start) / CLOCKS_PER_SEC << std::endl;
						bron_kerbosch_solver.do_bron_kerbosch_BT();
						graph_write(inGraph, bron_kerbosch_solver.get_maxClique(), OUTPUT_FILE.c_str());
						break;
					}
				default:
					{
						std::cout << "Wrong algorithm." << std::endl;
						system("pause>nul");
						return 0;
					}
				}
				std::cout << "Successfully written output to 'output.dot'." << std::endl;
				break;
			}
		}
	default:
		{
			std::cout << "Wrong option." << std::endl;
			system("pause>nul");
			return 0;
		}
	}

	std::cout << "Press any key to exit." << std::endl;
	system("pause>nul");
	return 0;

}